import { EChartType } from "../core/ChartType";
import ChartFormItem, { ChartFormItemContext } from "./ChartFormItem";
import { EChartFormItem, IChartFormItem, IMateData, TuseComputedFn, TinjectFn } from "./ChartItemType";
// const FormStateMap = new WeakMap<ChartForm, Array<FormState<any>>>();
export let ActiveChartForm: ChartForm | null = null;
export default class ChartForm {
    protected commonFormItem: { [key: string]: ChartFormItemContext } = {};
    private watchFn!: (computedConfig: IterableIterator<[string, FormState<any>]>) => void;
    private effectedPorps = new Map<string, Array<() => any>>();
    private computedMap = new Map<string, Array<() => any>>();
    private computedTargetMap = new Map<string, FormState<any>>();
    private effectFnComputedTargetMap = new Map<() => any, FormState<any>>();
    // private

    protected mateData: Array<IMateData> = [];
    protected titleForm: ChartFormItemContext;
    protected subTitleForm: ChartFormItemContext;
    protected limitForm: ChartFormItemContext;
    protected chartType: ChartFormItemContext;
    protected subChartType: ChartFormItemContext;
    private tmpFormContexts: Array<ChartFormItemContext> = [];
    private tmpComputeds = new WeakMap<FormState<any>, () => void>();
    public renderFunc!: (config: { [key: string]: IChartFormItem }, mateData: Array<IMateData>) => void;
    private blackItemList: string[] = [
        "subChartType", "chartType"
    ];
    private isEChartForm: boolean = true;
    constructor(
        formCreater?: () => any, isEChartForm: boolean = true,) {
        this.isEChartForm = isEChartForm;
        this.useFormState("titleForm", this.titleForm = new ChartFormItemContext({
            label: "标题",
            value: "",
            placeHolder: "请输入图标标题",
            // name: "titleForm",
            datas: "",
            type: EChartFormItem.Input
        }));
        this.useFormState("subTitleForm", this.subTitleForm = new ChartFormItemContext({
            label: "副标题",
            value: "",
            placeHolder: "请输入图标标题",
            // name: "subTitleForm",
            datas: "",
            type: EChartFormItem.Input
        }));
        this.useFormState("limitForm", this.limitForm = new ChartFormItemContext({
            label: "数据限制",
            value: "",
            placeHolder: "请输入图标标题",
            // name: "limitForm",
            datas: 0,
            type: EChartFormItem.Limit
        }));
        this.useFormState("chartType", this.chartType = new ChartFormItemContext({
            label: "图标类型",
            value: "",
            placeHolder: "图标类型",
            // name: "title",
            shouldRender: false,
            datas: "",
            type: EChartFormItem.Input
        }));
        this.useFormState("subChartType", this.subChartType = new ChartFormItemContext({
            label: "图标子类型",
            value: "",
            placeHolder: "图标子类型",
            // name: "title",
            shouldRender: false,
            datas: "",
            type: EChartFormItem.Input
        }));
        this.useComputed("title", [this.titleForm, this.subTitleForm], () => {
            const title = this.titleForm.data;
            const subTitle = this.subTitleForm.data;
            return {
                text: title,
                subtext: subTitle
            }
        });
        if (formCreater) {
            ActiveChartForm = this;
            const result = formCreater();
            // this._useFormState.bind(this),
            // this._useComputed.bind(this),
            // this._injectState.bind(this));
            ActiveChartForm = null;
            for (let key in result) {
                if (result[key] instanceof ChartFormItemContext) {
                    this.useFormState(key, result[key]);
                }
                if (result[key] instanceof FormState) {
                    const effectFn = this.tmpComputeds.get(result[key])
                    effectFn && this.effectFnComputedTargetMap.set(effectFn, result[key]);
                    this.computedTargetMap.set(key, result[key]);
                }
            }

        }
    }
    _injectState(propName: string | string[]) {
        if (!(propName instanceof Array)) {
            propName = [propName];
        }
        return propName.map(prop => this.commonFormItem[prop]);
    }
    setComputeWatcher(watchFn: (configs: IterableIterator<[string, FormState<any>]>) => void) {
        this.watchFn = watchFn
    }
    _useFormState(formItemContext: IChartFormItem) {
        const currentContext = new ChartFormItemContext(formItemContext);
        this.tmpFormContexts.push(currentContext);
        return currentContext;
    }
    _useComputed<T>(props: Array<ChartFormItemContext> | ChartFormItemContext, effectFn: () => any) {
        if (!(props instanceof Array)) {
            props = [props];
        }
        const computedTarget = FormStateCreater<T>(this, effectFn());
        props.forEach(prop => {
            this.computedMap.set(prop.name, [...(this.computedMap.get(prop.name) || []), effectFn]);
        })
        this.tmpComputeds.set(computedTarget, effectFn)
        return computedTarget;
    }
    protected useFormState(key: string, formItemContext: ChartFormItemContext) {
        formItemContext.setItemName(key);
        this.commonFormItem[key] = formItemContext;
    }






    useComputed<T>(computedName: string, props: Array<ChartFormItemContext> | ChartFormItemContext, effectFn: () => any) {
        let computedPropNames: string[] = [];
        if (!(props instanceof Array)) {
            props = [props];
        }
        const computedTarget = FormStateCreater<T>(this, effectFn());
        props.forEach(prop => {
            this.computedMap.set(prop.name, [...(this.computedMap.get(prop.name) || []), effectFn]);
        })
        this.effectFnComputedTargetMap.set(effectFn, computedTarget);
        this.computedTargetMap.set(computedName, computedTarget);
        return computedTarget;
    }
    public setFormState(key: string, data: any) {

        this.commonFormItem[key].setItemDatas(data);
        this.dispatchComputed(key);
    }
    public setSubChartType(type: number) {
        console.log("setSubChartType");
        this.setFormState("subChartType", type);
    }
    private isblockReturnName(key: string) {
        if (this.blackItemList.indexOf(key) >= 0) {
            return true;
        }
        return !this.isEChartForm && (key == "subTitleForm" || key == "titleForm");
    }
    public getCommonFormRenderConfig(): { [key: string]: IChartFormItem } {
        let result: { [key: string]: IChartFormItem } = {};
        for (let key in this.commonFormItem) {
            if (!this.isblockReturnName(key))
                result[key] = this.commonFormItem[key].currentChartForm;
        }

        return result;
    }
    private dispatchComputed(key: string) {
        const computedFn = this.computedMap.get(key);
        (computedFn || []).forEach(fn => {
            const computedTarget = this.effectFnComputedTargetMap.get(fn);
            if (computedTarget) {
                computedTarget.setState(computedFn ? fn() : null);
                if (this.watchFn) {
                    this.watchFn(this.computedTargetMap.entries());
                }
            }
        })

    }
    /**
     * 获取所有form配置项目
     */
    // abstract getChartFormConfig(): { [key: string]: any };
    /**
    * 获取所有form配置项目
    */
    getChartFormConfig(): { [key: string]: any } {
        let result: any = {};
        for (let key in this.commonFormItem) {
            result[key] = this.commonFormItem[key].currentChartForm.current
        }
        return result;
    }
    /**
     * 获取所有form配置项目
     */
    getChartFormRenderConfig() {
        const result: { [key: string]: IChartFormItem } = {
            ...this.getCommonFormRenderConfig()
        };
        return result;
    }
}

export function FormStateCreater<T>(target: ChartForm, stateValue: T) {
    const state = new FormState<T>(stateValue);
    return state;
}

export class FormState<T>{
    private _state: T;
    constructor(init: T) {
        this._state = init;
    }
    get current() {
        return this._state;
    }
    setState(value: T) {
        this._state = value;
    }
}